#include "gldrawer.h"
#include "paintdata.h"
#include "../geometry/polygon.h"
#include "../geometry/grid.h"
#include "../tests/segmentrasterization.h"
#include <QtGui/QMouseEvent>
#include <cstdio>


GLDrawer::GLDrawer(paint_data_t * data, QWidget * parent) : QGLWidget(parent), data_(data)
{
    setMouseTracking(true);
    QObject::connect(data_, SIGNAL(updated()), this, SLOT(repaint()));
}

void GLDrawer::initializeGL()
{
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_COLOR_MATERIAL);
    glEnable(GL_BLEND);
    glEnable(GL_POLYGON_SMOOTH);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glClearColor(0, 0, 0, 0);
}

void GLDrawer::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, w, 0, h);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void GLDrawer::paintGL()
{
    glColor3f(0, 0, 0.4);
    glClearColor(0.8, 0.8, 0.8, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    paintPolygon();
    paintRay();
    //paintRasterization();
    paintGrid();
}

void GLDrawer::mousePressEvent(QMouseEvent * event)
{
    std::cout << event->x() << "   " << this->height() - event->y() << std::endl;
    point_t point(event->x(), this->height() - event->y());
    data_->to_process_point(point);
}

void GLDrawer::mouseMoveEvent(QMouseEvent *event)
{
    //printf("%d, %d\n", event->x(), event->y());
}

void GLDrawer::keyPressEvent(QKeyEvent* event)
{
    std::cout << "key_pressed" << std::endl;
    switch (event->key())
    {
    case Qt::Key_Escape:
        close();
        break;
    default:
        event->ignore();
        break;
    }
}

void GLDrawer::paintPolygon()
{
    for(size_t n = 0; n != data_->polygon().size(); ++n)
    {
        contour_t contour = data_->polygon()[n];
        if(n > 0) glColor3f(0.5, 0.5, 0.5);
        for (size_t i = 0; i != contour.size(); ++i)
        {
            if(data_->current_contour() == n && i == contour.size() - 1) 
            {
                glPointSize(16);
                glBegin(GL_POINT);
                glVertex2f(contour[i].x, contour[i].y);
                glEnd();
                
                glLineWidth(5);
            }
            else glLineWidth(2);
            glBegin(GL_LINE);
            glVertex2f(contour[i].x, contour[i].y);
            if(i != contour.size() - 1)
                glVertex2f(contour[i + 1].x, contour[i + 1].y);
            else
                glVertex2f(contour[0].x, contour[0].y);
            glEnd();
            if(data_->is_current_point(contour[i])) {
                glPointSize(10);
                glBegin(GL_POINT);
                glVertex2f(contour[i].x, contour[i].y);
                glEnd();
            }
        }
    }
    glLineWidth(2);
}

void GLDrawer::paintRay()
{
    /*glColor3f(0.5, 0.0, 0.0);
    glBegin(GL_LINE);
    glVertex2f(data_->user_point().x, data_->user_point().y);
    glVertex2f(-100, data_->user_point().y);
    glEnd();*/
    if(data_->is_current_point(data_->user_point())) {
        glColor3f(0.8, 0.5, 0.0);
    }
    glPointSize(10);
    glBegin(GL_POINT);
    glVertex2f(data_->user_point().x, data_->user_point().y);
    glEnd();
}

void GLDrawer::paintGrid()
{
    glEnable(GL_ALPHA_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    grid_t grid = data_->grid();
    for(size_t i = 0; i < grid.size(); ++i)
    {
        //if(!grid[i].empty())
        //{
            std::vector<point_t> points;
            points.push_back(point_t(grid[i].center().x - data_->cell_size()/2, grid[i].center().y - data_->cell_size()/2));
            points.push_back(point_t(grid[i].center().x - data_->cell_size()/2, grid[i].center().y + data_->cell_size()/2));
            points.push_back(point_t(grid[i].center().x + data_->cell_size()/2, grid[i].center().y + data_->cell_size()/2));
            points.push_back(point_t(grid[i].center().x + data_->cell_size()/2, grid[i].center().y - data_->cell_size()/2));

            if(grid[i].center_in())
                glColor4d(0.0, 0.5, 0.0, 0.7);
            else
                glColor4d(0.0, 0.5, 0.0, 0.2);
            glBegin(GL_POLYGON);
            glVertex2d(points[0].x, points[0].y);
            glVertex2d(points[1].x, points[1].y);
            glVertex2d(points[2].x, points[2].y);
            glVertex2d(points[3].x, points[3].y);
            glEnd();

            glColor4d(0.0, 0.5, 0.0, 0.7);
            glBegin(GL_LINE_LOOP);
            glVertex2d(points[0].x, points[0].y);
            glVertex2d(points[1].x, points[1].y);
            glVertex2d(points[2].x, points[2].y);
            glVertex2d(points[3].x, points[3].y);
            glEnd();
        //}
    }

    glDisable(GL_BLEND);
    glDisable(GL_ALPHA_TEST);

}

void GLDrawer::paintRasterization()
{
    glEnable(GL_ALPHA_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    polygon_t polygon = data_->polygon();
    inserter f;

    for(size_t j = 1; j < polygon[0].size(); ++j)
    {
        segment_t seg(polygon[0][j - 1], polygon[0][j]);
        std::vector<cell_t> res = rasterize(seg, data_->cell_size(), boost::ref(f));
        std::cout << j << ") " << res.size() << std::endl;

        for(size_t i = 0; i < res.size(); ++i)
        {
            std::vector<point_t> points;
            points.push_back(point_t(res[i].center().x - data_->cell_size()/2, res[i].center().y - data_->cell_size()/2));
            points.push_back(point_t(res[i].center().x - data_->cell_size()/2, res[i].center().y + data_->cell_size()/2));
            points.push_back(point_t(res[i].center().x + data_->cell_size()/2, res[i].center().y + data_->cell_size()/2));
            points.push_back(point_t(res[i].center().x + data_->cell_size()/2, res[i].center().y - data_->cell_size()/2));

            glColor4d(0.0, 0.5, 0.0, 0.2);
            glBegin(GL_POLYGON);
            glVertex2d(points[0].x, points[0].y);
            glVertex2d(points[1].x, points[1].y);
            glVertex2d(points[2].x, points[2].y);
            glVertex2d(points[3].x, points[3].y);
            glEnd();

            glColor4d(0.0, 0.5, 0.0, 0.7);
            glBegin(GL_LINE_LOOP);
            glVertex2d(points[0].x, points[0].y);
            glVertex2d(points[1].x, points[1].y);
            glVertex2d(points[2].x, points[2].y);
            glVertex2d(points[3].x, points[3].y);
            glEnd();
        }
    }
    glDisable(GL_BLEND);
    glDisable(GL_ALPHA_TEST);

}
